<?php

declare(strict_types=1);

namespace App\Servers;

/**
 * websocket服务类
 * 作者 薛原
 * 实现消息推送和保持用户连接
 * 这块感觉有些问题还没调通
 */
use Hyperf\Contract\OnOpenInterface;
use Hyperf\Contract\OnCloseInterface;
use Hyperf\Contract\OnMessageInterface;
use Swoole\Http\Request;
use Swoole\WebSocket\Frame;


class Websocket implements OnOpenInterface, OnCloseInterface, OnMessageInterface
{
    //在线用户列表
    private $onlineUsers = [];

    /**
     * 连接建立时触发
     */
    public function onOpen($server, Request $request): void
    {
        // 从请求中获取用户ID（需要前端在连接时传递token）
        $userId = $this->authenticate($request);

        if ($userId) {
            $this->onlineUsers[$userId] = $request->fd;

            // 加入用户专属频道
            $server->join("user:{$userId}");

            // 发送连接成功消息
            $server->push($request->fd, json_encode([
                'type' => 'connected',
                'data' => ['user_id' => $userId]
            ]));

            Log::info("WebSocket连接建立: 用户{$userId}, FD{$request->fd}");
        } else {
            $server->close($request->fd);
        }
    }

    /**
     * 收到消息时触发
     */
    public function onMessage($server, Frame $frame): void
    {
        $data = json_decode($frame->data, true);

        if (!isset($data['type'])) {
            return;
        }

        switch ($data['type']) {
            case 'ping':
                // 心跳检测
                $server->push($frame->fd, json_encode(['type' => 'pong']));
                break;
        }
    }

    /**
     * 连接关闭时触发
     */
    public function onClose($server, int $fd, int $reactorId): void
    {
        $userId = array_search($fd, $this->onlineUsers);

        if ($userId) {
            unset($this->onlineUsers[$userId]);
        }
    }

    /**
     * 发送通知给指定用户
     */
    public function sendNotification(int $userId, array $notification): void
    {
        if (isset($this->onlineUsers[$userId])) {
            $fd = $this->onlineUsers[$userId];

            $message = json_encode([
                'type' => 'notification',
                'data' => $notification
            ]);

            $this->server->push($fd, $message);
        }
    }

    /**
     * 广播通知给所有用户
     */
    public function broadcastNotification(array $notification): void
    {
        $message = json_encode([
            'type' => 'notification',
            'data' => $notification
        ]);

        foreach ($this->onlineUsers as $fd) {
            $this->server->push($fd, $message);
        }
    }

    private function authenticate(Request $request): ?int
    {
        $token = $request->get['token'] ?? null;

        if (!$token) {
            return null;
        }
        $tokenData = json_decode(base64_decode($token),true);
        $user_id = ( isset($tokenData['acl']) && isset($tokenData['acl']['user_id']) )?$tokenData['acl']['user_id']:null;
        return $user_id;
    }

    private function handleSubscribe($server, int $fd, array $data): void
    {
        if (isset($data['channel'])) {
            $server->join($data['channel']);
        }
    }

    private function handleUnsubscribe($server, int $fd, array $data): void
    {
        if (isset($data['channel'])) {
            $server->leave($data['channel']);
        }
    }
}